﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics.LinearAlgebra.Single;

namespace CudaTranslator
{
    //klasa do obliczeń macierzowych
    class MatrixMath
    {
        string environment;
        //konstruktor domyślny
        public MatrixMath() {
            environment = "CPU";
        }

        //konstruktor z ustawianiem środowiska obliczeń
        public MatrixMath(string _environement)
        {
            environment = _environement;
        }

        //mnożenie macierzy
        public float[,] Multiply(int nrowsA, int ncolA,int ncolB,int nrowsB,float[,] A,float[,] B) {
            if (ncolA != nrowsB) {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }
            var a = new DenseMatrix(A);
            var b = new DenseMatrix(B);
            var c = a * b;
            return c.ToArray();
        }

        //dodawanie macierzy
        public float[,] Add(int nrowsA, int ncolA,  int nrowsB, int ncolB, float[,] A, float[,] B)
        {
            if (ncolA != ncolB  )
            {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of columns of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            if (nrowsA != nrowsB)
            {
                Console.WriteLine("Error: The numbers of rows of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            var a = new DenseMatrix(A);
            var b = new DenseMatrix(B);
            var c = a + b;
            return c.ToArray();
        }

        //odejmowanie macierzy
        public float[,] Minus(int nrowsA, int ncolA, int ncolB, int nrowsB, float[,] A, float[,] B)
        {
            if (ncolA != ncolB)
            {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of columns of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            if (nrowsA != nrowsB)
            {
                Console.WriteLine("Error: The numbers of rows of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            var a = new DenseMatrix(A);
            var b = new DenseMatrix(B);
            var c = a - b;
            return c.ToArray();
        }

        //dzielenie macierzy - mnożenie przez odwrotnosc
        public float[,] Div(int nrowsA, int ncolA, int ncolB, int nrowsB, float[,] A, float[,] B)
        {
            if (ncolA != nrowsB)
            {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }
            var a = new DenseMatrix(A);
            var b = new DenseMatrix(B);
            var c = a * b.Inverse();
            return c.ToArray();
        }

        //dzielenie elementow macierzy
        public float[,] DivDot(int nrowsA, int ncolA, int ncolB, int nrowsB, float[,] A, float[,] B)
        {
            if (ncolA != ncolB)
            {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of columns of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            if (nrowsA != nrowsB)
            {
                Console.WriteLine("Error: The numbers of rows of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            float[,] c=new float[nrowsA,ncolA];
            for (int i = 0; i < nrowsA; i++) {
                for (int j = 0; j < ncolA; j++) {
                    c[i, j] = A[i, j] / B[i, j];
                }
            }
                return c;
        }

        //mnożenie elementów macierzy
        public float[,] MultiplyDot(int nrowsA, int ncolA, int ncolB, int nrowsB, float[,] A, float[,] B)
        {
            if (ncolA != ncolB)
            {
                Console.WriteLine("Error: The numbers of columns of A does not match the number of columns of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            if (nrowsA != nrowsB)
            {
                Console.WriteLine("Error: The numbers of rows of A does not match the number of rows of B/n" + ncolA + "!=" + nrowsB);
                return null;
            }

            float[,] c = new float[nrowsA, ncolA];
            for (int i = 0; i < nrowsA; i++)
            {
                for (int j = 0; j < ncolA; j++)
                {
                    c[i, j] = A[i, j] * B[i, j];
                }
            }
            return c;
        }

        //odwrotnosc macierzy
        public float[,] Inverse(float[,] A)
        {
            return ((new DenseMatrix(A)).Inverse()).ToArray();
        }

        //transpozycja macierzy
        public float[,] Transpose(float[,] A)
        {
            return ((new DenseMatrix(A)).Transpose()).ToArray();
        }

    }
}
